/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bff.api.manager;

import com.inspur.edp.bef.api.lcp.AuthInfo;
import com.inspur.edp.bef.api.lcp.IStandardLcp;
import com.inspur.edp.bef.api.parameter.retrieve.RespectiveRetrieveResult;
import com.inspur.edp.bef.api.parameter.retrieve.RetrieveParam;
import com.inspur.edp.bff.api.manager.context.TimeStampContext;
import com.inspur.edp.bff.api.param.retrieve.RetrieveChildResult;
import com.inspur.edp.bff.api.param.retrieve.RetrieveResult;
import com.inspur.edp.bff.entity.RetrieveDefaultParam;
import com.inspur.edp.bff.entity.defaultvalue.VoDefaultValue;
import com.inspur.edp.cef.api.action.EditResult;
import com.inspur.edp.cef.api.manager.serialize.CefSerializeContext;
import com.inspur.edp.cef.api.request.RequestInfo;
import com.inspur.edp.cef.api.response.ResponseContext;
import com.inspur.edp.cef.api.response.ResponseInfo;
import com.inspur.edp.cef.api.rootManager.ICefRootManager;
import com.inspur.edp.cef.entity.changeset.IChangeDetail;
import com.inspur.edp.cef.entity.condition.EntityFilter;
import com.inspur.edp.cef.entity.dependenceTemp.Pagination;
import com.inspur.edp.cef.entity.entity.IEntityData;
import com.inspur.edp.cef.spi.entity.resourceInfo.ModelResInfo;
import com.inspur.edp.cef.variable.api.manager.IVariableManager;
import com.inspur.edp.commonmodel.api.ICMManager;
import com.inspur.edp.web.help.api.LookupQueryParam;
import com.inspur.edp.web.help.api.LookupResult;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * 标准的本地消费者代理，提供了外部程序调用的基本的操作接口，比如CRUD
 * 继承自{@link com.inspur.edp.commonmodel.api.ICMManager} 以及{@link com.inspur.edp.cef.api.rootManager.ICefRootManager}
 * <p>创建本类实例请使用{@link IFSManagerFactory}
 */
public interface IFSManager extends ICefRootManager, ICMManager {
    /**
     * 功能连接
     *
     * @param parentSessionID 功能sessionID
     * @return
     */
    String connect(String parentSessionID);

    /**
     * 尝试功能连接
     */
    void tryConnect();

    /**
     * 关闭当前session
     */
    void close();

    /**
     * 1.取消当前业务实体上已提交到缓存、但未保存到持久化中的变更集；
     * <p>
     * 2.释放当前业务实体下所有的数据锁；
     * 取消内部实现调用{@link IStandardLcp#cancel()}，详情请看{@link IStandardLcp}
     */
    void cancel();

    /**
     * 返回给请求的响应数据，包括返回给前端的消息以及后台产生的变更集数据。
     *
     * @return
     * @see ResponseContext
     */
    ResponseContext getResponseContext();

    /**
     * 获取当前视图对象的FSManager上下文
     *
     * @return
     * @see IFSManagerContext
     */
    IFSManagerContext getBffContext();

    /**
     * 新增一条视图对象主表数据，实体数据中带有默认值。关于默认值的说明可以参考{@link #retrieveDefault(VoDefaultValue)}。
     *
     * @return 实体数据
     * @see IEntityData
     */
    IEntityData retrieveDefault();

    /**
     * 新增一条特定ID的视图对象主表数据，实体数据中字段带有默认值。实体数据默认值可参考{@link #retrieveDefault(VoDefaultValue)}。
     */
    IEntityData retrieveDefault(String dataId);

    /**
     * 新增一条视图对象主表数据，实体数据中带有传入的默认值。默认值的来源有：
     * <ul><li>字段类型固有默认值（通常为{@code null}，如果在WebIde上将字段的“默认为空”属性设置为false，则使用字段的非{@code null}默认值，
     * 如整数类型({@link Integer})为0，浮点类型({@link BigDecimal})为0.0，文本类型({@link String})为""等）；
     * <li>通过WebIde设计器中给字段设置的默认值；
     * <li>通过{@code defaultValues}参数传入的默认值；
     * <li>字段上设置的新增时生成的编号规则；
     * <li>通过新增后联动计算设置的默认值；</ul>
     * 以上默认值规则按顺序从上至下进行，上面的默认值与下面的默认值如有重复，下面将覆盖上面。
     *
     * @param defaultValue 传入的默认值，默认值中不能包含主键字段，默认值参数设置参考{@link VoDefaultValue}
     * @return 新增的主表实体数据
     * @see IEntityData
     */

    IEntityData retrieveDefault(VoDefaultValue defaultValue);

    /**
     * 根据默认值参数新增一组视图对象主表数据，生成的数据条数由传入参数defaultParam上的getVoDefaultValues()个数决定
     *
     * @param defaultParam
     * @return 视图对象主表数据列表
     * @see ArrayList<IEntityData>
     * @see RetrieveDefaultParam
     */

    ArrayList<IEntityData> retrieveDefaultBatch(RetrieveDefaultParam defaultParam);

    /**
     * 新增一条视图对象的从(从)表数据。默认值规则与{@link #retrieveDefault(VoDefaultValue)}一致。
     * 新增从（从）表数据时，必须提供一个上级数据的Id，且这个Id所代表的上级数据必须存在。上级数据的Id将被赋值到从（从）表数据的ParentId字段上。
     * 如果上级数据不存在，将会引发编号为{@code GSP_ADP_BEF_2004}的{@link com.inspur.edp.bef.api.exceptions.BefException}异常。
     * <ul><li>1. 新增从表数据时，{@code nodeCodes}中要包含从表实体编号，{@code hierachyIds}中要包含主表数据的唯一标识；
     * <li>2.该方法不只支持新增从表数据，同样的也可以新增从从表数据。新增从从表数据时，{@code nodeCodes}中要包含从从表所属的从表实体编号，
     * 以及从从表的实体编号，{@code hierachyIds}中要包括对应主表数据的唯一标识、子表数据的唯一标识。</ul>
     * <p>
     * 下面通过一个例子说明{@code nodeCodes}和{@code hierachyIds}两个参数如何构造。
     * <p>
     * 假设有一个业务实体，其主表为A，节点编号为A，A下有从表B，节点编号为B，B下有从从表C，节点编号为C。
     * <p>
     * 如果需要新增一条B（从表）实体数据，此时两个参数分别应为：
     * <ul><li>{@code nodeCodes}：{@code ArrayList<String> nodeCodes=new ArrayList();nodeCodes.add("B");}
     * <li>{@code hierachyIds}：{@code ArrayList<String> hierachyIds=new ArrayList();hierachyIds.add("A实体数据Id");}</ul>
     * <p>
     * 如果需要新增一条C（从从表）实体数据，此时两个参数分别应为：
     * <ul><li>{@code nodeCodes}：{@code ArrayList<String> nodeCodes=new ArrayList();nodeCodes.add("B");nodeCodes.add("C");}
     * <li>{@code hierachyIds}：{@code ArrayList<String> hierachyIds=new ArrayList();hierachyIds.add("A实体数据Id");hierachyIds.add("B实体数据Id");}</ul>
     * 再下层的，以此类推
     * 此外，如果是生成型的VO元数据，在WebIde中点击生成代码菜单后，在生成的I{VO编号}Service接口中会针对每个从（从）表
     * 生成对应的新增方法。上述例子中，将在IAService接口中自动生成如下几个方法（实现也是自动生成的）：
     * <ul><li>retrieveDefaultB(String aId);
     * <li>retrieveDefaultB(String aId, String bId);</ul>
     * 可以看到，使用这些生成的方法，参数更加清晰、使用不易犯错，因此对于生成型VO推荐使用自动生成的新增从（从）表方法。
     *
     * @param nodeCodes   新增数据的从(从)表的实体编号列表
     * @param lierachyIds 新增从(从)表数据的所属实体数据的唯一标识列表
     * @return 新增的视图对象从(从)表数据
     * @see IEntityData
     */
    IEntityData retrieveDefaultChild(java.util.ArrayList<String> nodeCodes, java.util.ArrayList<String> lierachyIds);

    /**
     * 根据指定的id新增一组视图对象的从(从)表数据。
     * 用法与{@link #retrieveDefaultChild(ArrayList, ArrayList)}基本一致，唯一的区别是{@link #retrieveDefaultChild(ArrayList, ArrayList)}
     * 新增的数据的ID是自动生成的，而使用此方法可以通过第三个参数指定ID。需要注意指定的ID必须与已存在数据不同。
     *
     * @param nodeCodes   要新增数据的从(从)表的实体编号列表
     * @param lierachyIds 新增从(从)表数据的所属实体数据的唯一标识列表
     * @param ids         新增从(从)表数据的所属实体数据的唯一标识列表
     * @return 新增的从(从)表实体数据列表
     * @see #retrieveDefaultChild(ArrayList, ArrayList)
     * @see IEntityData
     */
    ArrayList<IEntityData> retrieveDefaultChild(java.util.ArrayList<String> nodeCodes, java.util.ArrayList<String> lierachyIds, ArrayList<String> ids);

    /**
     * 使用指定的默认值新增一条视图对象的从(从)表数据。
     * 除了第三个参数外，其他用法与{@link #retrieveDefaultChild(ArrayList, ArrayList)}一致。
     *
     * @param nodeCodes    要新增数据的从(从)表的实体编号
     * @param lierachyIds  新增从(从)表数据的所属实体数据的唯一标识
     * @param defaultValue 从(从)表新增数据使用的默认值, 其中不包含主键，详细信息可参考{@link #retrieveDefault(VoDefaultValue)}
     * @return 新增的从(从)表实体数据
     * @see #retrieveDefaultChild(ArrayList, ArrayList)
     * @see IEntityData
     */
    IEntityData retrieveDefaultChild(java.util.ArrayList<String> nodeCodes, java.util.ArrayList<String> lierachyIds, VoDefaultValue defaultValue);


    /**
     * 使用指定的默认值新增一组视图对象的从(从)表数据。
     * 除了第三个参数外，其他用法与{@link #retrieveDefaultChild(ArrayList, ArrayList)}一致。
     *
     * @param nodeCodes    要新增数据的从(从)表的实体编号
     * @param lierachyIds  新增从(从)表数据的所属实体数据的唯一标识
     * @param defaultValue 从(从)表新增数据使用的默认值, 其中不包含主键，详细信息可参考{@link #retrieveDefault(VoDefaultValue)}
     * @return 新增的从(从)表实体数据
     * @see #retrieveDefaultChild(ArrayList, ArrayList)
     * @see IEntityData
     */
    ArrayList<IEntityData> retrieveDefaultChilds(java.util.ArrayList<String> nodeCodes, java.util.ArrayList<String> lierachyIds, ArrayList<VoDefaultValue> defaultValue);

    /**
     * 使用指定的默认值批量新增视图对象的从(从)表数据。
     * 除了第三个参数外，其他用法与{@link #retrieveDefaultChild(ArrayList, ArrayList)}一致。
     *
     * @param nodeCodes   新增数据的从(从)表的实体编号列表
     * @param lierachyIds 新增从(从)表数据的所属实体数据的唯一标识列表
     * @param param       从(从)表新增数据使用的默认值, 其中不包含主键，详细信息可参考{@link #retrieveDefaultBatch(RetrieveDefaultParam)}
     * @return 新增的从(从)表视图对象实体数据列表
     * @see #retrieveDefaultChild(ArrayList, ArrayList)
     * @see IEntityData
     */
    ArrayList<IEntityData> retrieveDefaultChild(java.util.ArrayList<String> nodeCodes, java.util.ArrayList<String> lierachyIds,
                                                RetrieveDefaultParam param);

    /**
     * 使用不加锁的方式检索指定ID的实体数据，检索出来的数据带着所有的子表数据。
     * <p>注意，通过此方法检索得到的数据不应进行任何修改，强行修改可能导致异常，如需修改请使用{@link #modify(IChangeDetail)}。
     * <p>如需对检索行为进行更精细化的控制，请使用{@link #retrieve(String, RetrieveParam)}
     *
     * @param dataID 实体数据的唯一标识
     * @return 检索的返回结果，包含实体数据和加锁是否成功等，实体数据中带着所有子表数据信息，子表数据信息可从{@link IEntityData#getChilds()}的方法中获取
     * @see #retrieve(String, RetrieveParam)
     */
    IEntityData retrieve(String dataID);

    /**
     * 加锁并检索数据。如果加锁失败会抛出异常。
     *
     * @param dataId
     * @return 检索结果
     */
    EditResult edit(String dataId);

    /**
     * 检索指定ID的视图对象主表数据，可指定是否加锁
     * <p>注意，如果加锁失败，此方法不会抛出异常，而是通过将返回值上的{@link RespectiveRetrieveResult#getLockFailed()}置为false代表加锁失败。
     * <p>注意，通过此方法检索得到的数据不应进行任何修改，强行修改可能导致异常，如需修改请使用{@link #modify(IChangeDetail)}。
     * <p>如果希望在加锁失败后抛出异常以中止后续代码逻辑，应使用{@link #edit(String)}方法，或增加逻辑进行判断。
     * <p>在自定义动作中执行实体动作前通常需要先进行检索，如果实体动作中可能修改数据，
     * 那么推荐使用{@link #edit(String)}方法进行加锁并检索，而不是retrieve方法。
     * 因为{@code retrieve}方法默认不进行加锁这一点容易被开发人员忽略，同时也不容易通过测试发现问题。
     *
     * @param dataId        实体数据的唯一标识
     * @param retrieveParam 检索参数
     * @return 检索的返回结果
     * @see #edit(String)
     */
    IEntityData retrieve(String dataId, RetrieveParam retrieveParam);

    /**
     * 检索一组指定ID的视图对象主表数据，加锁的方式可指定，检索参数可参考{@link #retrieve(String, RetrieveParam)}
     * <p>注意，通过此方法检索得到的数据不应进行任何修改，强行修改可能导致异常，如需修改请使用{@link #modify(IChangeDetail)}。
     *
     * @param dataIds       一组实体数据的唯一标识
     * @param retrieveParam 检索参数
     * @return 检索的返回结果
     */
    java.util.List<IEntityData> retrieve(java.util.ArrayList<String> dataIds, RetrieveParam retrieveParam);

    /**
     * 检索指定ID的视图对象主表数据，加锁的方式可指定检索，检索参数可参考{@link #retrieve(String, RetrieveParam)}
     * <p>注意，通过此方法检索得到的数据不应进行任何修改，强行修改可能导致异常，如需修改请使用{@link #modify(IChangeDetail)}。
     * <p>
     * 下面通过一个例子说明{@code nodeCodes}和{@code hierachyIds}两个参数如何构造。
     * <p>
     * 假设有一个业务实体，其主表为A，节点编号为A，A下有从表B，节点编号为B，B下有从从表C，节点编号为C。
     * <p>
     * 如果需要检索一条B（从表）实体数据，此时两个参数分别应为：
     * <ul><li>{@code nodeCodes}：{@code ArrayList<String> nodeCodes=new ArrayList();nodeCodes.add("B");}
     * <li>{@code lierachyIds}：{@code ArrayList<String> lierachyIds=new ArrayList();lierachyIds.add("A实体数据Id");}</ul>
     * <p>
     * 如果需要检索一条C（从从表）实体数据，此时两个参数分别应为：
     * <ul><li>{@code nodeCodes}：{@code ArrayList<String> nodeCodes=new ArrayList();nodeCodes.add("B");nodeCodes.add("C");}
     * <li>{@code IdsachyIds}：{@code ArrayList<String> lierachyIds=new ArrayList();lierachyIds.add("A实体数据Id");lierachyIds.add("B实体数据Id");}</ul>
     * 再下层的，以此类推
     *
     * @param nodeCodes     检索数据的从(从)表的实体编号列表
     * @param lierachyIds   检索从(从)表数据的所属实体数据的唯一标识列表
     * @param retrieveParam 检索参数
     * @return 检索的返回结果
     */
    IEntityData retrieveChild(java.util.ArrayList<String> nodeCodes, java.util.ArrayList<String> lierachyIds, RetrieveParam retrieveParam);

    /**
     * 检索一组指定ID的视图对象主表数据，根据参数{@code ids}参数确认个数，可指定加锁方式
     * <p>
     * 其余参数可参考{@link #retrieveChild(ArrayList, ArrayList, RetrieveParam)}
     *
     * @param nodeCodes     检索数据的从(从)表的实体编号列表
     * @param lierachyIds   检索从(从)表数据的所属实体数据的唯一标识列表
     * @param ids           要检索数据从表或从从表的数据id列表
     * @param retrieveParam 检索参数
     * @return
     */
    ArrayList<IEntityData> retrieveChild(java.util.ArrayList<String> nodeCodes, java.util.ArrayList<String> lierachyIds, ArrayList<String> ids, RetrieveParam retrieveParam);

    /**
     * 将业务实体数据的变更集提交到内存。若想将变更集提交到数据库，需要在调用Modify方法之后，再调用Save方法。
     * <p>使用变更集既可以修改主表数据，也可以修改从（从）表数据。
     * <p>变更集的构造方法可以<a href="https://open.inspuronline.com/iGIX/#/document/mddoc/docs-gsp-cloud-ds%2Fdev-guide-beta%2Fspecial-subject%2FBE-related%2F%E5%8F%98%E6%9B%B4%E9%9B%86%E4%BD%BF%E7%94%A8.md">点击这里</a>查看。
     *
     * @param change 实体数据的变更集
     */
    void modify(IChangeDetail change);

    /**
     * 根据过滤条件查询视图对象主表数据。
     *
     * <p>该方法不会对数据进行加锁（相比{@link #retrieve(String, RetrieveParam)}）。
     * <p>返回结果不包含任何子表数据，也不包含未持久化的修改。
     * <p>数据量过大时可能导致性能问题，建议使用带过滤条件的{@link #query(EntityFilter)}方法进行查询。
     * <p>对查询结果进行任何修改都{@code 不会}被持久化，如需修改数据请使用{@link #modify(IChangeDetail)}。
     *
     * @return 业务实体主表数据集合，不含任何子表
     * @see QueryResult
     */
    QueryResult query(EntityFilter filter);

    /**
     * 根据过滤条件查询视图对象子表数据。
     *
     * <p>该方法不会对数据进行加锁（相比{@link #retrieve(String, RetrieveParam)}）。
     * <p>返回结果不包含任何子表数据，也不包含未持久化的修改。
     * <p>数据量过大时可能导致性能问题，建议设置滤条件进行查询。
     * <p>对查询结果进行任何修改都{@code 不会}被持久化，如需修改数据请使用{@link #modify(IChangeDetail)}。
     *
     * @param nodeCodes 节点编号列表，此处传值可参考{@link #retrieveChild(ArrayList, ArrayList, RetrieveParam)}
     * @param filter    查询条件
     * @return 业务实体子表本身数据集合
     * @see QueryResult
     */
    QueryResult queryChild(List<String> nodeCodes, EntityFilter filter);

    /**
     * 根据过滤条件查询视图对象子表数据。
     *
     * <p>该方法不会对数据进行加锁（相比{@link #retrieve(String, RetrieveParam)}）。
     * <p>返回结果不包含任何子表数据，也不包含未持久化的修改。
     * <p>数据量过大时可能导致性能问题，建议设置滤条件进行查询。
     * <p>对查询结果进行任何修改都{@code 不会}被持久化，如需修改数据请使用{@link #modify(IChangeDetail)}。
     *
     * @param nodeCode 要查询的从表或者从从表等的节点编号
     * @param filter   查询条件
     * @return 业务实体子表本身数据集合
     * @see QueryResult
     */
    QueryResult queryChild(String nodeCode, EntityFilter filter);

    QueryResult queryWithAuthInfo(EntityFilter filter, AuthInfo authInfo);

    /**
     * 暂未支持
     *
     * @param param
     * @param pageInfo
     * @param extendCond
     * @return
     */
    java.util.List<IEntityData> query(String param, Pagination pageInfo, String extendCond);

    /**
     * 将指定ID的业务实体数据的删除变更集提交到内存。若需要将该删除变更集提交到数据库，需要在调用{@link #delete(String)}方法后，再调用{@link #save()}方法。
     *
     * @param dataID 实体数据的唯一标识
     */
    void delete(String dataID);

    /**
     * 批量将指定ID的业务实体数据的删除变更集提交到内存。若需要将该删除变更集提交到数据库，需要在调用{@link #delete(String)}方法后，再调用{@link #save()}方法。
     *
     * @param dataIds 实体数据的唯一标识的集合
     */
    void delete(java.util.ArrayList<String> dataIds);

    /**
     * 将指定ID的业务实体数据的删除变更集提交到内存，并调用用{@link #save()}方法，将该删除变更集提交到数据库。
     *
     * @param dataID 实体数据的唯一标识
     */
    void deleteAndSave(String dataID);

    /**
     * 删除从(从)表数据
     * <p>
     * 参数nodeCodes、hierachyIdLis设置可参考{@link #retrieveChild(ArrayList, ArrayList, RetrieveParam)}方法中的nodeCodes以及lierachyIds参数设置
     *
     * @param nodeCodes      要删除数据的从(从)表的实体编号列表
     * @param hierachyIdList 要删除数据的从(从)表的所属实体数据的唯一标识列表
     * @param ids            要删除的从(从)表数据的唯一标识列表
     */
    void deleteChild(java.util.List<String> nodeCodes, java.util.List<String> hierachyIdList, java.util.List<String> ids);

    /**
     * 保存数据：将服务器端的变更数据保存到数据库中。
     */
    void save();

    /**
     * 创建视图对象的主对象数据实例
     *
     * @return 创建的视图对象的主表数据实例
     * @see IEntityData
     */
    IEntityData createData();

    /**
     * 创建新的视图对象的子对象数据实例。
     *
     * @param childCode 子表对象节点编号
     * @return 创建的视图对象的子对象数据实例。
     * @see IEntityData
     */
    IEntityData createData(String childCode);

    /**
     * 根据指定的帮助查询参数获取帮助数据
     *
     * @param codeName   设有帮助字段的视图对象的节点编号
     * @param labelId    帮助字段标签
     * @param queryParam 帮助查询参数
     * @return 查询获取到的帮助数据。
     * @see LookupResult
     */
    LookupResult getElementHelp(String codeName, String labelId, String queryParam);

    /**
     * 根据指定的帮助查询参数获取帮助数据
     *
     * @param codeName   设有帮助字段的视图对象的节点编号
     * @param labelId    帮助字段标签
     * @param queryParam 帮助查询参数
     * @return 查询获取到的帮助数据
     * @see LookupResult
     */
    LookupResult getElementHelp(String codeName, String labelId, LookupQueryParam queryParam);

    /**
     * 获取默认值类类型
     */
    java.lang.Class getDefaultValueType();

    /**
     * 获取变更集类类型
     */
    java.lang.Class getChangeInfoType();

    /**
     * 获取请求类类型
     */
    java.lang.Class getRequsetType();


    /**
     * 将客户端发起的请求json反序列化RequestInfo对象
     *
     * @param requestStr 客户端发起的请求json串
     * @param contex     序列化反序列化上下文
     * @return 反序列化后的请求实体
     * @see RequestInfo
     */
    RequestInfo buildRequest(String requestStr, CefSerializeContext contex);

    /**
     * 对于客户端的请求，创建相应的响应信息对象
     *
     * @return 返回响应的信息
     * @see ResponseInfo
     */
    ResponseInfo createResponse();

    /**
     * 处理客户端发起的请求
     *
     * @param request 客户端发起的请求{@link ResponseInfo}对象
     */
    void dealRequest(RequestInfo request);

    /**
     * 处理视图对象上设置的变量的变更集
     *
     * @param change 变量变更信息
     *               <p>变更集的构造方法可以<a href="https://open.inspuronline.com/iGIX/#/document/mddoc/docs-gsp-cloud-ds%2Fdev-guide-beta%2Fspecial-subject%2FBE-related%2F%E8%87%AA%E5%AE%9A%E4%B9%89%E5%8F%98%E9%87%8F.md">点击这里</a>查看。
     * @see IChangeDetail
     */
    void dealVariable(IChangeDetail change);

    /**
     * 构造响应信息
     *
     * @param returnValue 服务端返回的响应信息
     * @return 服务端响应实体信息
     * @see ResponseInfo
     */
    ResponseInfo buildResponse(Object returnValue);

    /**
     * 创建变量管理类
     *
     * @return 变量管理接口实例
     * @see IVariableManager
     */
    IVariableManager createVariableManager();

    /**
     * 国际化资源
     *
     * <p> 可以通过{@link ModelResInfo}拿到想要的国际化资源项
     *
     * @return 国际化资源信息
     * @see ModelResInfo
     */
    ModelResInfo getModelInfo();

    /**
     * 根据检索条件获取到指定数据Id的数据
     *
     * @param dataId 要检索的数据id
     * @return 根据检索条件获取到的指定
     * @parm param 检索参数
     */
    RetrieveResult retrieveWithChildPagination(String dataId, com.inspur.edp.bff.api.param.retrieve.RetrieveParam param);

    /**
     * 按索引检索子表
     *
     * @param nodeCodes
     * @param hierachyIds
     * @param pagination
     * @return
     */
    RetrieveChildResult retrieveChildByIndex(ArrayList<String> nodeCodes, ArrayList<String> hierachyIds, Pagination pagination);

    /**
     * 执行自定义动作
     *
     * @param actionCode 动作编号
     * @param params     参数以及参数值字典，带有顺序
     * @return 返回执行动作后的值
     */
    Object executeCustomAction(String actionCode, LinkedHashMap<String, Object> params);

    /**
     * 创建并保存一条数据，数据直接保存到数据库，并重新检索到缓存中。
     *
     * @param data 空的视图对象实体数据
     * @return 新增保存后的新数据
     * <p> 内部重新调用{@link #retrieve(String)}方法，将数据从数据库检索出来，返回的{@link IEntityData}和数据库中保持一致。
     * @see IEntityData
     */
    IEntityData createAndSave(IEntityData data);

    /**
     * 修改并保存一条数据，数据直接保存到数据库，并重新检索到缓存中。
     *
     * @param data 要修改的实体数据
     * @return 修改保存后的新数据
     * <p> 内部重新调用{@link #retrieve(String)}方法，将数据从数据库检索出来，返回的{@link IEntityData}和数据库中保持一致。
     * @see IEntityData
     */
    IEntityData modifyAndSave(IEntityData data);

    /**
     * 批量删除数据，并保存
     *
     * @param dataIds 要删除保存数据的集合
     */
    void deleteAndSave(ArrayList<String> dataIds);

    /**
     * 是否是解析型
     *
     * @return 解析型的标识
     */
    boolean isEngine();

    /**
     * 序列化服务端响应
     *
     * @param responseInf 服务端响应对象
     * @param contex      序列化反序列化上下文
     * @return 服务端响应的json结构
     */
    String serializeResponseInfo(ResponseInfo responseInf, CefSerializeContext contex);


    /**
     * 获取Headers
     *
     * @return
     */
    List<String> getAcceptHeaderNames();

    /**
     * 给Header赋值
     *
     * @param name
     * @param value
     */
    void setHeader(String name, String value);

    /**
     * 将vo变更集转换为be变更集
     *
     * @param voChanges vo上的变更集
     * @return 转换后的be变更集集合
     */
    ArrayList<IChangeDetail> convertChangefromVo(ArrayList<IChangeDetail> voChanges);

    /**
     * 将be变更集转换为vo变更集
     *
     * @param sourceChanges be变更集
     * @return 转换后的vo变更集
     */
    ArrayList<IChangeDetail> convertChange2Vo(ArrayList<IChangeDetail> sourceChanges);

    /**
     * 客户端发起请求，给当前session枷锁
     */
    void onBeforeRequest();

    /**
     * 释放当前session的锁
     */
    void onFinallyRequest();

    /**
     * 默认值集合{@link ArrayList<VoDefaultValue>}的反序列化
     *
     * <p>返回后的默认值，详情可参考{@link #retrieveDefault(VoDefaultValue)}方法中的{@link VoDefaultValue}
     *
     * @param nodeCodes 视图对象的节点编号集合
     * @param nodeJson  默认值json结构
     * @return 反序列化后的默认值集合
     */
    ArrayList<VoDefaultValue> deserializeVoDefaultValues(List<String> nodeCodes, String nodeJson);

    /**
     * 单个{@link VoDefaultValue}默认值的反序列化
     *
     * @param nodeCodes 视图对象的节点编号集合
     * @param nodeJson  默认值json结构
     * @return
     */
    VoDefaultValue deserializeVoDefaultValue(List<String> nodeCodes, String nodeJson);

    /**
     * 视图对象主表默认值参数{@link RetrieveDefaultParam}的反序列化
     *
     * @param nodeJson 默认值参数{@link RetrieveDefaultParam}json结构
     * @return 反序列化后的视图对象主表默认值参数
     * @see RetrieveDefaultParam
     */
    RetrieveDefaultParam deserializerRetrieveDefaultParam(String nodeJson);

    /**
     * 视图对象从(从)表默认值参数{@link RetrieveDefaultParam}的反序列化
     *
     * @param nodeCodes 视图对象的节点编号集合，该参数的设置规则可参考{@link #retrieveChild(ArrayList, ArrayList, RetrieveParam)}中的第一个参数设置
     * @param nodeJson  默认值参数{@link RetrieveDefaultParam}json结构
     * @return 反序列化后的视图对象从(从)表默认值参数
     * @see RetrieveDefaultParam
     */
    RetrieveDefaultParam deserializerRetrieveDefaultParam(List<String> nodeCodes, String nodeJson);

    /**
     * 获取时间戳上下文
     *
     * @return
     */
    TimeStampContext getTimeStampContext();

    /**
     * 给时间戳上下文赋值
     *
     * @param value
     */
    void setTimeStampContext(TimeStampContext value);

    /**
     * 分级码去重，支持权限过滤
     *
     * @param fjnPropertyName 分级码字段标签
     * @param filter          过滤条件
     * @param parentLayer     父级级数
     * @param authInfo        权限信息
     * @return
     */
    List<String> getDistinctFJM(String fjnPropertyName, EntityFilter filter, Integer parentLayer, AuthInfo authInfo);

    boolean hasChanges();
}
